
<script setup lang="ts">
/* eslint-disable no-console */
// import { isDev, toggleDev } from '~/composables'

import { GamePlay } from '~/composables/logic'
import { Pointer } from '~/composables/pointer'

import type { BlockState } from '~/types'
const play = new GamePlay(9, 9, 9)
const logined = ref(false)
const now = $(useNow())
const timerMS = $computed(() => Math.round(((play.state.value.endMS ?? +now) - (play.state.value.startMS ?? +now)) / 1000))
const socket = window.io('http://192.168.1.154:3000/game')

// useStorage('vuesweeper-state', play.state)
const state = $computed(() => play.board)
const localUser = ref({
  id: '',
  username: '',
})
const mineRest = $computed(() => {
  if (!play.state.value.mineGenerated)
    return play.mines
  return play.blocks.reduce((a, b) => a - (b.flagged ? 1 : 0), play.mines)
})

function newGame(difficulty: 'easy' | 'medium' | 'hard') {
  switch (difficulty) {
    case 'easy':
      play.reset(9, 9, 10)
      break
    case 'medium':
      play.reset(16, 16, 40)
      break
    case 'hard':
      // play.reset(16, 25, 99)
      play.reset(25, 25, 80)
      break
  }
  play.emit('stateNeedUpdate')
}

watchEffect(() => {
  play.checkGameState()
  // socket.emit('updateGameState', {
  //   id: localUser.value.id,
  //   gameState: toRaw(play.state.value),
  // })
})

play.on('click', (block: BlockState) => {
  console.log(block)
})

socket.on('gameStateUpdated', (data: any) => {
  console.log('gameStateUpdated')
  if (data.id !== localUser.value.id) {
    console.log('update from server')
    const gameState = data.gameState
    play.width = gameState.width
    play.height = gameState.height
    play.mines = gameState.mines
    play.state.value = gameState.state
  }
})
play.on('stateNeedUpdate', () => {
  console.log('stateNeedUpdate')
  socket.emit('updateGameState', {
    id: localUser.value.id,
    gameState: {
      width: play.width,
      height: play.height,
      mines: play.mines,
      state: toRaw(play.state.value),
    },
  })
})
let localPointer: any = null
const remotePointers = new Map<string, Pointer>()
let localGameSynced = false
const onMouseMove = function(event) {
  socket.emit('msgToServer', {
    id: localUser.value.id,
    coord: {
      top: event.clientY,
      left: event.clientX,
    },
  })
  if (localPointer) {
    localPointer.updatePosition({
      coord: {
        left: event.clientX,
        top: event.clientY,
      },
    })
  }
}
socket.on('connect', (data: any) => {
  const id = socket.id
  console.log(socket)
  localUser.value.id = id
  // socket.emit('register', {id})
})
socket.on('userIn', (data: any) => {
  console.log('userIn', data)
  const users = data.users
  const gameState = data.gameState
  for (const userId in users) {
    if (userId === localUser.value.id) continue
    if (!remotePointers.get(userId)) {
      const pointer = new Pointer(users[userId])
      remotePointers.set(userId, pointer)
      console.log('create remote pointer')
    }
  }

  if (!gameState) {
    localGameSynced = true
    socket.emit('updateGameState', {
      id: localUser.value.id,
      gameState: {
        width: play.width,
        height: play.height,
        mines: play.mines,
        state: toRaw(play.state.value),
      },
    })
  }
  else if (!localGameSynced) {
    console.log('sync from server...', gameState)
    play.width = gameState.width
    play.height = gameState.height
    play.mines = gameState.mines
    play.state.value = gameState.state
    localGameSynced = true
  }
})
socket.on('userOut', (id: string) => {
  console.log('userOut')
  const pointer = remotePointers.get(id)
  pointer?.dispose()
})
socket.on('update', (data: any) => {
  const pointer = remotePointers.get(data.id)
  pointer?.updatePosition(data)
})
function onLogined(info: any) {
  logined.value = true
  localPointer = new Pointer(info)
  localUser.value.username = info.username
  socket.emit('registerUser', {
    id: localUser.value.id,
    username: info.username,
    avatar: info.avatar,
  })
}
</script>

<template>
  <div style="height: 100%;" @mousemove="onMouseMove">
    Minesweeper

    <div flex="~ gap1" justify-center p4>
      <button btn @click="play.reset()">
        New Game
      </button>
      <button btn @click="newGame('easy')">
        Easy
      </button>
      <button btn @click="newGame('medium')">
        Medium
      </button>
      <button btn @click="newGame('hard')">
        Hard
      </button>
    </div>

    <div flex="~ gap-10" justify-center>
      <div font-mono text-2xl flex="~ gap-1" items-center>
        <div i-carbon-timer />
        {{ timerMS }}
      </div>
      <div font-mono text-2xl flex="~ gap-1" items-center>
        <div i-mdi-mine />
        {{ mineRest }}
      </div>
    </div>

    <div p5 w-full overflow-auto>
      <div
        v-for="row, y in state"
        :key="y"
        flex="~"
        items-center justify-center w-max ma
      >
        <MineBlock
          v-for="block, x in row" :key="x"
          :block="block"
          @click="play.onClick(block)"
          @lrclick="play.autoExpand(block)"
          @contextmenu.prevent="play.onRightClick(block)"
        />
      </div>
    </div>

    <!-- <div flex="~ gap-1" justify-center>
      <button btn @click="toggleDev()">
        {{ isDev ? 'DEV' : 'NORMAL' }}
      </button>
    </div> -->

    <Confetti :passed="play.state.value.status === 'won'" />
    <Login v-if="!logined" @logined="onLogined" />
  </div>
</template>
